package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import jdk.jshell.execution.LocalExecutionControl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;


    @Autowired
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 下单或充值选择微信支付，对接微信支付获取小程序拉起微信支付所需参数
     *
     * @param paymentType
     * @param orderNo
     * @return {小程序所需参数Map}
     */
    @Override
    public Map<String, String> createJsapi(String paymentType, String orderNo) {
        try {
            //1.保存本地交易记录
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);
            String paymentStatus = paymentInfo.getPaymentStatus();
            if (!SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentStatus)) {
                throw new RuntimeException("状态有误");
            }

            //2.1 创建对接小程序支付业务对象
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
            //2.2 创建预下单请求对象 封装支付相关参数
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
            //TODO 测试阶段付款设置为1分 将来从本地交易记录中获取真实价格
            amount.setTotal(1);
            request.setAmount(amount);
            request.setAppid(wxPayV3Config.getAppid());
            request.setMchid(wxPayV3Config.getMerchantId());
            request.setDescription(paymentInfo.getContent());
            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
            request.setOutTradeNo(orderNo);
            //TODO 目前小程序还未上线，测试中只允许应用下开发者进行付款 写我的
            Payer payer = new Payer();
            payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");
            request.setPayer(payer);
            //2.3 调用下单方法
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
            if (response != null) {
                String timeStamp = response.getTimeStamp();
                String nonceStr = response.getNonceStr();
                String packageVal = response.getPackageVal();
                String signType = response.getSignType();
                String paySign = response.getPaySign();
                Map<String, String> map = new HashMap<>();
                map.put("timeStamp", timeStamp);
                map.put("nonceStr", nonceStr);
                map.put("package", packageVal);
                map.put("signType", signType);
                map.put("paySign", paySign);
                return map;
            }
            return null;
        } catch (RuntimeException e) {
            log.error("[微信支付]下单异常：{}", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据商户订单编号查询订单支付结果
     *
     * @param orderNo
     * @return
     */
    @Override
    public boolean queryPayStatus(String orderNo) {
       /* //1.创建对接小程序支付业务对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
        //2.根据商户侧订单编号查询订单支付状态
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setOutTradeNo(orderNo);
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        if (transaction != null) {
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                return true;
            }
        }*/

        //假设用户已经付款成功（商家入账）只需处理核心业务：更新本地交易记录
        //1. 手动创建微信交易对象
        Transaction transaction = new Transaction();
        transaction.setOutTradeNo(orderNo);
        transaction.setTransactionId("WX"+ IdUtil.getSnowflakeNextId());
        //2.调用核心业务处理本地交易记录
        paymentInfoService.updatePaymentInfo(transaction);
        return true;
    }

    /**
     * 提供给微信支付调用：用户微信付款成功后，微信通知商户支付结果
     *
     * @param request
     * @return {code:"SUCCESS",message:"成功"}
     */
    @Override
    public Map<String, String> notifyPayResult(HttpServletRequest request) {
        //1.验签-避免出现虚假通知或支付结果在网络传输中被恶意篡改
        //1.1 从请求头中获取封装请求参数对象数据
        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        log.info("签名：{}，序列号：{}，随机数：{}，时间戳：{}，签名类型：{}", signature, serial, nonce, timestamp);
        //1.2 获取请求体中参数
        String body = PayUtil.readData(request);
        log.info("请求体：{}", body);
        //1.3 将请求相关参数封装到RequestParam对象中
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(body)
                .build();
        //1.4 创建通知解析器对象NotificationParser
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        //1.5 调用解析器解析方法进行验签及获取明文业务数据
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        //2.幂等性处理
        if (transaction != null) {
            //微信交易订单编号
            String transactionId = transaction.getTransactionId();
            //2.1 构建幂等性保证key
            String key = "pay:weixin:" + transactionId;
            //2.2 尝试存入Redis
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, transactionId, 25, TimeUnit.HOURS);
            if (flag) {
                try {
                    //3.验证商户侧金额跟支付结果中金额 TODO 测试金额固定是1分 将来从本地交易记录中获取验证
                    Transaction.TradeStateEnum tradeState = transaction.getTradeState();
                    if(tradeState == Transaction.TradeStateEnum.SUCCESS){
                        Integer payerTotal = transaction.getAmount().getPayerTotal();
                        if (payerTotal.intValue() == 1) {
                            //4.核心业务处理：处理本地交易记录及对应订单或充值状态
                            paymentInfoService.updatePaymentInfo(transaction);
                            //5.正确应答微信结果
                            Map<String, String> map = new HashMap<>();
                            map.put("code", "SUCCESS");
                            map.put("message", "成功");
                            return map;
                        }
                    }
                } catch (Exception e) {
                    redisTemplate.delete(key);
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }
}
